/*
   FIX pause free resources
 * LoggerRptForm.java
 *
 * Copyright (C) 2007 Irving Bunton
 * http://code.google.com/p/jlogmicro/source
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
// Expand to define MIDP define
@DMIDPVERS@
// Expand to define CLDC define
@DCLDCVERS@
// Expand to define logging define
@DLOGDEF@
// Expand to define DFEATUREFORMDEF define
@DFEATUREFORMDEF@
//#ifdef DLOGGING
package net.sf.jlogmicro.util.presentation;

import java.util.Enumeration;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.UnsupportedEncodingException;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.Gauge;
import javax.microedition.rms.*;

@DFEATUREFORMIMPORTDEF@
import net.sf.jlogmicro.util.logging.Logger;
import net.sf.jlogmicro.util.logging.FormHandler;
import net.sf.jlogmicro.util.logging.RecStoreHandler;
import net.sf.jlogmicro.util.logging.BufferedHandler;
import net.sf.jlogmicro.util.logging.Handler;
import net.sf.jlogmicro.util.logging.LogManager;
import net.sf.jlogmicro.util.logging.Level;

public class LoggerRptForm extends
//#ifdef DFEATUREFORM
FeatureForm
//#else
Form
//#endif
implements CommandListener, Runnable {
    final private MIDlet midlet;
    private CommandListener cmdListner;
    private boolean fineLoggable = false;
    private boolean finestLoggable = false;
    private boolean traceLoggable = false;
    private Logger logger = null;
	private BufferedHandler bhandler = null; // Buffered handler
	private RecordStore recStore = null; // Rec store
	private RecordEnumeration erec = null;
	private Form formStore = null; // Form store
    private Command     clearLogCmd; // clear record store command
    private Command     stopLogCmd; // stop showing record store command
    private Command     firstLogCmd; // show first record store command
    private Command     saveLogCmd; // save/open record store command
    private Command     exitCmd;// The exit command
	protected boolean procCmd = false;
	protected Command exCmd = null;
	private Displayable exDisp = null;
    private int loop = 0;
	//#ifdef DFEATUREFORM
    private boolean     background = false;   // Flag to continue looping
	//#else
    private boolean     background = true;   // Flag to continue looping
	//#endif

	public LoggerRptForm(LogManager logManager, MIDlet midlet,
			CommandListener cmdListner, String reqHandler) {
		super(reqHandler + " Log");
		this.midlet = midlet;
		//#ifndef DFEATUREFORM
		this.cmdListner = cmdListner;
		//#endif
        logger = Logger.getLogger(logManager, "LoggerRptForm", null);
        try {
            fineLoggable = logger.isLoggable(Level.FINE);
            finestLoggable = logger.isLoggable(Level.FINEST);
            traceLoggable = logger.isLoggable(Level.TRACE);
			logger.finest("reqHandler=" + reqHandler);
			for (Enumeration eHandlers =
					logger.getParent().getHandlers().elements();
					eHandlers.hasMoreElements();) {
				Object ohandler = eHandlers.nextElement();
				String hname = ohandler.getClass().getName();
				logger.finest("ohandler=" + hname + "," + ohandler);
				if (hname.equals(reqHandler)) {
					if (ohandler instanceof BufferedHandler) {
						bhandler = (BufferedHandler)ohandler;
						logger.finest("bhandler=" + bhandler);
					}
					if (ohandler instanceof RecStoreHandler) {
						recStore = (RecordStore)bhandler.getView();
						logger.finest("recStore=" + recStore);
					} if (ohandler instanceof FormHandler) {
						formStore = (Form)bhandler.getView();
						logger.finest("formStore=" + formStore);
					}
				}
			}
			if (finestLoggable) {logger.finest("cmdListner=" + ((cmdListner == null) ? "null" : cmdListner.getClass().getName()) + "," + cmdListner);}
        } catch (Throwable e) {
            logger.severe("LoggerRptForm " + e.getMessage(), e);
        }

		try {
			logger.info("Test info.");
			logger.fine("Test fine.");
			logger.finer("Test finer.");
			logger.finest("Test finest.");
			logger.trace("Test trace.");
			Alert m_about = getAbout();
			clearLogCmd     = new Command("Clear", Command.SCREEN, 1);
			firstLogCmd     = new Command("First", Command.SCREEN, 2);
			saveLogCmd     = new Command("Save", Command.SCREEN, 3);
			stopLogCmd     = new Command("Stop", Command.STOP, 4);
			exitCmd     = new Command("Exit", Command.SCREEN, 5);
			super.addCommand( clearLogCmd );
			super.addCommand( firstLogCmd );
			super.addCommand( saveLogCmd );
			super.addCommand( stopLogCmd );
			super.addCommand( exitCmd );
			//#ifndef DFEATUREFORM
			//#ifdef DCLDCV11
			new Thread(this, this.getClass().getName()).start();
			//#else
			new Thread(this).start();
			//#endif
			//#endif
		} catch (Throwable e) {
			System.out.println("Constructor " + e.getClass().getName() + " " 
					+ e.getMessage());
			e.printStackTrace();
		}
	}

	/* FIX
    public void setCommandListener(CommandListener c) {
		super.setCommandListener(c);
	} */

	public void commandAction(Command cmd, Displayable cdisp) {
		synchronized(this) {
			this.exCmd = cmd;
			this.exDisp = cdisp;
			this.procCmd = true;
			if ((cmd == exitCmd) || (cmd == stopLogCmd)) {
				background = false;
			}
		}
		//#ifndef DFEATUREFORM
		wakeup(3);
		//#endif
	}

	public void run() {
        long lngStart;
        long lngTimeTaken;
		do {
			try {
				Command ccmd = null;
				Displayable cdisp = null;
				boolean cprocCmd = false;
				synchronized(this) {
					cprocCmd = procCmd;
					ccmd = exCmd;
					cdisp = exDisp;
				}
				if (cprocCmd) {
					synchronized(this) {
						procCmd = false;
					}
					try {
						//#ifdef DLOGGING
						if (fineLoggable) {logger.fine("cprocCmd,ccmd,cdisp=" + ccmd.getLabel() + "," + cdisp);}
						//#endif
						if (ccmd == clearLogCmd) {
							try {
								if (bhandler instanceof RecStoreHandler) {
									if (erec != null) {
										erec.destroy();
									}
									bhandler.removeView();
									refreshRecStore();
								} else if (bhandler instanceof FormHandler) {
									bhandler.removeView();
									refreshRecStore();
								}
							} catch (Throwable e) {
								if (bhandler instanceof RecStoreHandler) {
									logException("clearLogCmd recStore", recStore, e);
								} else if (bhandler instanceof FormHandler) {
									logException("clearLogCmd formStore", formStore, e);
								}
							}

						} else if (ccmd == firstLogCmd) {
							if (bhandler instanceof RecStoreHandler) {
								refreshRecStore();
								showRecStore();
							} else if (bhandler instanceof FormHandler) {
								refreshFormStore();
								showFormStore();
							}
						} else if (ccmd == saveLogCmd) {
							try {
								if (bhandler instanceof RecStoreHandler) {
									bhandler.closeView();
									recStore = (RecordStore)bhandler.openView(true);
								} else if (bhandler instanceof FormHandler) {
									bhandler.closeView();
									formStore = (Form)bhandler.openView(true);
								}
							} catch (Throwable e) {
								logException("formStore", formStore, e);
							}
						} else if (ccmd == exitCmd) {
							bhandler.closeView();
							midlet.notifyDestroyed();
							background = false;
						} else if ((cmdListner != null) &&
								(cmdListner != this)) {
							cmdListner.commandAction(ccmd, cdisp);
							background = false;
						}
					} catch (Throwable e) {
						logException("formStore", formStore, e);
					}
				}
				lngStart = System.currentTimeMillis();
				lngTimeTaken = System.currentTimeMillis()-lngStart;
				if(lngTimeTaken<200L) {
					synchronized(this) {
						if (loop-- > 0) {
							super.wait(200L-lngTimeTaken);
						}
					}
				}
			} catch (InterruptedException e) {
				logger.severe("run interrupted stopping " + e.getMessage(), e);
				break;
			} catch (Throwable e) {
				System.out.println("run " + e.getClass().getName() + " " 
						+ e.getMessage());
				e.printStackTrace();
			}
		} while (background);
	}

	private void refreshRecStore() {
		recStore = (RecordStore)bhandler.getView();
		if (recStore == null) {
			System.out.println("run recStore not opened");
			recStore = (RecordStore)bhandler.openView(
					false);
			System.out.println("new recStore=" + recStore);
		}
	}

	private void showRecStore() {
		try {
			final int nbrs = recStore.getNumRecords();
			System.out.println("run recStore # recs " +
					nbrs);
			if (erec != null) {
				erec.destroy();
			}
			Gauge gauge = null;
			//#ifdef DMIDP10
			final int fsize = super.size();
			if (fsize > nbrs) {
				final int diff = fsize - nbrs;
				final int diffDelta = diff / 16;
				gauge = new Gauge("Deleting form items",
						false, diffDelta + 1, 0);
				int ic = diff;
				super.insert(0, gauge);
				for (int i = fsize; ic > 0; i--, ic--) {
					super.delete(i);
					if ((i & 15) == 0) {
						gauge.setValue((diff - ic) / 16);
					}
				}
			}
			//#else
			super.deleteAll();
			//#endif
			final int csize = super.size();
			if (nbrs <= 0) {
				return;
			}
			final int cdiffDelta = nbrs / 16;
			gauge = new Gauge(
					((csize <= 1) ?
					 "Adding" : "modifying") + " log records on screen " + nbrs,
					false, cdiffDelta + 1, 0);
			if (csize > 0) {
				super.set(0, gauge);
			} else {
				super.append(gauge);
			}
			erec = recStore.enumerateRecords(null, null,
					false);
			int gctr = 0;
			for (int i = 0;erec.hasNextElement(); i++) {
				if ((i & 15) == 0) {
					gauge.setValue(gctr++);
					if (!background) {
						break;
					}
				}
				byte[] brec = erec.nextRecord();
				DataInputStream dis = new DataInputStream(
						new ByteArrayInputStream(brec));
				long time = dis.readLong();
				byte[] irec = new byte[brec.length];
				int blen = dis.read(irec, 0, brec.length);
				String msg = null;
				try {
					msg = new String(irec, 0, blen, "UTF-8");
				} catch (UnsupportedEncodingException e) {
					msg = new String(irec, 0, blen);
				}
				super.append(msg + "\n");
			}
			super.delete(0);
		} catch (Throwable e) {
			logException("recStore", recStore, e);
		}
	}

	private void refreshFormStore() {
		formStore = (Form)bhandler.getView();
		if (formStore == null) {
			System.out.println("run formStore not opened");
			formStore = (Form)bhandler.openView(
					false);
			System.out.println("new formStore=" + formStore);
		}
	}

	private void showFormStore() {
		try {
			final int nbrs = formStore.size();
			System.out.println("run formStore # recs " + nbrs);
			//#ifdef DMIDP10
			int ix = super.size() - 1;
			while (ix >= 0) {
				super.delete(ix--);
			}
			//#else
			super.deleteAll();
			//#endif
			final int flen = formStore.size();
			int ex = 0;
			for (int i = 0; i < flen; i++) {
				StringItem item = null;
				try {
					item = (StringItem)formStore.get(i);
				} catch (Throwable e) {
					logException("formStore showFormStore formStore.get(i)=" +
						formStore.get(i), formStore, e);
					if (ex++ > 3) {
						throw e;
					}
				}
				try {
					super.append(new StringItem(null, item.getText()));
				} catch (Throwable e) {
					logException("formStore showFormStore append item=" +
						item, formStore, e);
					if (ex++ > 3) {
						throw e;
					}
				}
			}
		} catch (Throwable e) {
			logException("formStore", formStore, e);
		}
	}

	private void logException(String objName, Object obj, Throwable e) {
		e.printStackTrace();
		String msg = "run first name,class name,e,e msg=" +
			objName + "," + ((obj == null) ? "null" : obj.getClass().getName()) + "," +
			e.getClass().getName() +
			"," + e.getMessage();
		System.out.println(msg);
		if (super.size() > 0) {
			super.insert(0, new StringItem("Exception:\n",
						msg));
		} else {
			super.append(new StringItem("Exception:\n",
						msg));
		}
	}

	public void wakeup(int loop) {
    
		synchronized(this) {
			this.loop += loop;
			super.notify();
		}
	}

    /**
	 * Create about alert.
	 * @author  Irving Bunton
	 * @version 1.0
	 */
	private Alert getAbout() {
		Alert about = new Alert("About RssReader",
"JLogMicro v@MIDLETVERS@ " +
 "Copyright (C) 2007 Irving Bunton " +
 " http://code.google.com/p/jlogmicro/source " +
 "This program is distributed in the hope that it will be useful, " +
 "but WITHOUT ANY WARRANTY; without even the implied warranty of " +
 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the " +
 "GNU General Public License for more details. " +
 "This program is free software; you can redistribute it and/or modify " +
 "it under the terms of the GNU General Public License as published by " +
 "the Free Software Foundation; either version 2 of the License, or " +
 "(at your option) any later version.  ", null, AlertType.INFO);
		about.setTimeout(Alert.FOREVER);
 
		return about;
	}

    public Form getFormStore() {
        return (formStore);
    }

}
//#endif
